﻿using System;
using System.Collections.Generic;
using System.Text;

namespace PW.Mini.SlepowronskiJ.Siec.Algorytmy
{
    [Serializable]
    public class StopMalySpadekStrategia : IStrategia
    {
        /// <summary>
        /// domyslna minimalna poprawa
        /// </summary>
        ///
        public const double domyslnaMinimalnaPoprawa = 0.0000001d;

        /// <summary>
        /// domyslan liczba iteracji z mala poprawa
        /// </summary>
        ///
        public const int domyslnaLiczbaIteracji = 500;

        /// <summary>
        /// minimalna poprawa ktora jest liczona do liczby 'zlych' iteracji, czyli takich bez poprawy
        /// wiekszej niz minimalna
        /// </summary>
        ///
        private readonly double minimalnaPoprawa;

        /// <summary>
        /// liczba iteracji bez poprawy wiekszej od minimalnej poprawy
        /// po przekroczeniu tej liczby siec powinna zaprzestac uczenia
        /// bo za duzo to juz sie nie nauczy
        /// </summary>
        ///
        private readonly int liczbaIteracji;

        /// <summary>
        /// osiagnieta liczba iteracji bez poprawy wiekszej niz minimalna poprawa
        /// </summary>
        ///
        private int liczbaZlychIteracji;

        /// <summary>
        /// minimalny osiagniety blad
        /// </summary>
        ///
        private double minBlad;

        /// <summary>
        /// ostatni blad
        /// </summary>
        ///
        private double ostatniBlad;

        /// <summary>
        /// flaga oznaczajaca ze nalezy zakonczyc uczenie, bo nastepuja za male poprawy bledow
        /// </summary>
        ///
        private bool shouldStop;

        #region konstruktory
        /// <summary>
        /// konsutruktor domyslny startuje z domyslnymi parametrami
        /// </summary>
        ///
        public StopMalySpadekStrategia() : this(domyslnaMinimalnaPoprawa, domyslnaLiczbaIteracji)
        {
        }

        /// <summary>
        /// konstruktor z parametrami po ktorych strategia okresla moment zatrzymania uczenia
        /// </summary>
        ///
        /// <param name="minimalnaPoprawa">wartosc minimalnej poprawy ktora jest liczona jako znaczaca</param>
        /// <param name="liczbaIteracji">liczba cykli bez znaczacych popraw przed zakonczeniem uczenia</param>
        public StopMalySpadekStrategia(double minimalnaPoprawa,
                                    int liczbaIteracji)
        {
            this.minimalnaPoprawa = minimalnaPoprawa;
            this.liczbaIteracji = liczbaIteracji;
            liczbaZlychIteracji = 0;
            minBlad = Double.MaxValue;
            ostatniBlad = -1;
        }
        #endregion

        #region IStrategia implementacja

        /// <summary>
        /// 
        /// </summary>
        ///
        public virtual void Init(int size)
        {
            shouldStop = false;
        }

        /// <summary>
        /// 
        /// </summary>
        ///
        public virtual void PostIteration()
        {
            if (ostatniBlad>-1)
            {
                if (Math.Abs(minBlad - Monitor.Instancja.BladSieci) < minimalnaPoprawa)
                {
                    ++liczbaZlychIteracji;
                    if (liczbaZlychIteracji > liczbaIteracji)
                        shouldStop = true;
                }
                else
                    liczbaZlychIteracji = 0;
            }
            ostatniBlad = Monitor.Instancja.BladSieci;
            minBlad = Math.Min(ostatniBlad, minBlad);
        }

        /// <summary>
        /// 
        /// </summary>
        ///
        public virtual void PreIteration()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        ///
        public virtual bool ShouldStop()
        {
            return shouldStop;
        }

        #endregion
    }
}